﻿using System.IO;
using System.Linq.Expressions;
using System.ServiceProcess;
using System;
using System.Linq;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using MongoDB;

namespace FutureTech.Data.MongoDB
{
        /// <summary>
        /// 
        /// </summary>
        public class MongoDataStorage
        {
                #region 构造函数

                /// <summary>
                /// Initializes a new instance of the <see cref="MongoDataStorage"/> class.
                /// </summary>
                /// <param name="ip">The ip.</param>
                /// <param name="port">The port.</param>
                /// <param name="dbName">Name of the database.</param>
                public MongoDataStorage(string ip, int port, string dbName)
                {
                                EnvironmentVerification();

                                Mongo = new Mongo("mongodb://" + ip +  ":" + port);

                                MongoDatabase = Mongo.GetDatabase(dbName);

                                Mongo.Connect();
                                
                }

                #endregion 构造函数

                #region 属性

                /// <summary>
                /// Gets the mongo.
                /// </summary>
                /// <value>
                /// The mongo.
                /// </value>
                public Mongo Mongo { get; private set; }

                /// <summary>
                /// Gets the mongo database.
                /// </summary>
                /// <value>
                /// The mongo database.
                /// </value>
                public IMongoDatabase MongoDatabase { get; private set; }

                #endregion 属性

                /// <summary>
                /// Environments the verification.
                /// </summary>
                /// <exception cref="System.InvalidOperationException">数据库服务启动失败</exception>
                private void EnvironmentVerification()
                {
                        var mongoDbServiceController = new ServiceController("MongoDB");

                        if (mongoDbServiceController.Status != ServiceControllerStatus.Running)
                        {
                                File.Delete(@"D:\MongoDB32\Data\mongod.lock");

                                mongoDbServiceController.Start();

                                mongoDbServiceController.WaitForStatus(ServiceControllerStatus.Running, TimeSpan.FromSeconds(3));

                                if (mongoDbServiceController.Status != ServiceControllerStatus.Running)
                                {
                                        throw new InvalidOperationException("数据库服务启动失败");
                                }
                        }
                }

                /// <summary>
                /// Inserts the specified attribute.
                /// </summary>
                /// <typeparam name="T"></typeparam>
                /// <param name="t">The attribute.</param>
                public void Insert<T>(T t) where T:class,IMongoKey
                {
                        ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
                                {
                                        IMongoCollection<T> collection = MongoDatabase.GetCollection<T>();
                                        collection.Insert(t);
                                }));
                }


                /// <summary>
                /// Deletes the specified attribute.
                /// </summary>
                /// <typeparam name="T"></typeparam>
                /// <param name="t">The attribute.</param>
                public void Delete<T>(T t) where T : class,IMongoKey
                {
                        Delete<T>(t.Key); 
                }

                /// <summary>
                /// Deletes the specified mongo key.
                /// </summary>
                /// <typeparam name="T"></typeparam>
                /// <param name="mongoKey">The mongo key.</param>
                public void Delete<T>(string mongoKey) where T : class,IMongoKey
                {
                        ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
                        {
                                IMongoCollection<T> collection = MongoDatabase.GetCollection<T>();
                                collection.Remove(i => i.Key == mongoKey);
                        }));
                        
                }

                /// <summary>
                /// Updates the specified attribute.
                /// </summary>
                /// <typeparam name="T"></typeparam>
                /// <param name="t">The attribute.</param>
                public void Update<T>(T t) where T : class,IMongoKey
                {
                        ThreadPool.QueueUserWorkItem(new WaitCallback(state =>
                        {
                                IMongoCollection<T> collection = MongoDatabase.GetCollection<T>();
                                collection.Update(t, (i => i.Key == t.Key));  
                        }));

                              
                }

                /// <summary>
                /// Selects the specified mongo key.
                /// </summary>
                /// <typeparam name="T"></typeparam>
                /// <param name="mongoKey">The mongo key.</param>
                /// <returns></returns>
                public T Select<T>(string mongoKey) where T : class,IMongoKey
                {

                        IMongoCollection<T> collection = MongoDatabase.GetCollection<T>();

                        var result = collection.FindOne(i => i.Key == mongoKey);

                        return result;
                }

                /// <summary>
                /// Selects the specified function.
                /// </summary>
                /// <typeparam name="T"></typeparam>
                /// <param name="func">The function.</param>
                /// <returns></returns>
                public List<T> Select<T>(Expression<Func<T, bool>> func) where T : class,IMongoKey
                {

                        IMongoCollection<T> collection = MongoDatabase.GetCollection<T>();

                        return collection.Linq().Where(func).ToList();
                }

                /// <summary>
                /// Selects this instance.
                /// </summary>
                /// <typeparam name="T"></typeparam>
                /// <returns></returns>
                public List<T> Select<T>() where T : class,IMongoKey
                {

                        IMongoCollection<T> collection = MongoDatabase.GetCollection<T>();

                        return collection.Linq().ToList();
                }
        }
}